/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
// BMS数据结构体（新协议：DD 03 状态(1) 长度(1) 数据(N) 校验(2) 77）
typedef struct {
    uint8_t header;        // 头帧 DD
    uint8_t cmd;           // 命令码 03
    uint8_t status;        // 状态码 00
    uint16_t dataLen;      // 数据长度（字节数）
    uint8_t data[64];      // 数据内容（最大64字节）
    uint16_t checksum;     // 校验结果
    uint8_t stopByte;      // 停止位 77
} BMS_Response_t;
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define U1_RX_LEN   5
#define U2_RX_LEN   6
#define U3_RX_LEN   6
#define RS485_CMD_LEN 7    // 0x03指令长度
#define RS485_RESP_LEN 64   // 接收缓冲长度（IDLE接收 + 累积组帧）
#define RS485_RESEND_INTERVAL_MS 100 // 若未收到应答，连续重发的间隔
#define BMS_HEADER 0xDD     // BMS头帧
#define BMS_STOP 0x77       // BMS停止位
#define BMS_CMD_03 0x03     // BMS命令码
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint8_t u1Rx[U1_RX_LEN];
uint8_t u2Rx[U2_RX_LEN];
uint8_t u3Rx[U3_RX_LEN];
uint8_t u1RxFlag = 0;
uint8_t u2RxFlag = 0;
uint8_t u3RxFlag = 0;

// RS485通讯相关变量
uint8_t rs485Cmd[RS485_CMD_LEN] = {0xDD, 0xA5, 0x03, 0x00, 0xFF, 0xFD, 0x77};  // 发送指令
uint8_t rs485Resp[RS485_RESP_LEN];         // 接收响应
uint8_t rs485RespFlag = 0;                 // 响应接收标志
uint8_t rs485TxFlag = 0;                   // 发送标志
uint16_t rs485RespLen = 0;                 // 实际接收长度（IDLE接收）
uint32_t lastTxTick = 0;                   // 上次发送时间戳
uint8_t rs485AccBuf[256];                  // 累积缓冲，用于组帧
uint16_t rs485AccLen = 0;                  // 累积缓冲长度

// BMS响应解析变量
BMS_Response_t bmsResponse;
uint8_t bmsParseFlag = 0;                  // BMS解析完成标志
/* USER CODE END PV */

/* Private function prototypes ---------------------------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
// 计算校验和（所有字节总和取反+1）
uint16_t calculateChecksum(uint8_t *data, uint16_t len);
// 解析BMS响应数据
uint8_t parseBMSResponse(uint8_t *rawData, uint16_t rawLen);
// 打印BMS数据
void printBMSData(BMS_Response_t *bms);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart == &huart1)
    {
        if (memcmp(u1Rx, "test\n", U1_RX_LEN) == 0)
        {
            u1RxFlag = 1;
        }
        HAL_UART_Receive_IT(&huart1, u1Rx, U1_RX_LEN);
    }
    else if (huart == &huart3)
    {
        if (memcmp(u3Rx, "U2TOU3", U3_RX_LEN) == 0)
        {
            u3RxFlag = 1;
        }
        HAL_UART_Receive_IT(&huart3, u3Rx, U3_RX_LEN);
    }
}

// 使用IDLE中断的接收回调，获取实际接收长度
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    if (huart == &huart2)
    {
        rs485RespLen = Size;
        if (Size > 0)
        {
            // 追加到累积缓冲
            if ((uint16_t)(rs485AccLen + Size) > sizeof(rs485AccBuf))
            {
                rs485AccLen = 0;
            }
            memcpy(&rs485AccBuf[rs485AccLen], rs485Resp, Size);
            rs485AccLen += Size;
            rs485RespFlag = 1;
        }
        // 重新启动IDLE接收，准备下次帧
        HAL_UARTEx_ReceiveToIdle_IT(&huart2, rs485Resp, RS485_RESP_LEN);
    }
}

// 计算校验和（所有字节总和取反+1）
uint16_t calculateChecksum(uint8_t *data, uint16_t len)
{
    uint32_t sum = 0;
    for (uint16_t i = 0; i < len; i++)
    {
        sum += data[i];
    }
    return (uint16_t)(~sum + 1);
}

// 解析BMS响应数据（新协议：DD 03 状态(1) 长度(1) 数据(N) 校验(2) 77）
uint8_t parseBMSResponse(uint8_t *rawData, uint16_t rawLen)
{
    if (rawLen < 7) return 0; // 最小长度检查

    // 检查头帧和停止位
    if (rawData[0] != BMS_HEADER || rawData[rawLen-1] != BMS_STOP)
    {
        return 0;
    }

    // 检查命令码
    if (rawData[1] != BMS_CMD_03)
    {
        return 0;
    }

    // 状态与数据长度（长度为1字节）
    uint8_t status = rawData[2];
    uint8_t dataLen = rawData[3];
    if (dataLen > sizeof(bmsResponse.data) || (dataLen + 7) != rawLen)
    {
        return 0;
    }
    if (status != 0x00)
    {
        // 非成功状态直接返回失败
        return 0;
    }

    // 校验和校验：从状态(含)开始到最后一个数据字节（不含DD与CMD）
    uint16_t calculatedChecksum = calculateChecksum(&rawData[2], 2 + dataLen);
    uint16_t rxChecksum = ((uint16_t)rawData[rawLen-3] << 8) | rawData[rawLen-2];
    if (calculatedChecksum != rxChecksum)
    {
        // 容错：有的BMS可能用 DD..DATA 求和或大小端不同，尝试常见变体
        uint16_t calc_from_dd = calculateChecksum(rawData, 4 + dataLen);
        uint16_t rx_swapped = ((uint16_t)rawData[rawLen-2] << 8) | rawData[rawLen-3];
        if (!(calculatedChecksum == rxChecksum || calc_from_dd == rxChecksum || calculatedChecksum == rx_swapped || calc_from_dd == rx_swapped))
        {
            // 打印一次失败的校验信息，便于调试
            char dbg[96];
            int n = sprintf(dbg, "CS fail: rx=0x%04X calc(ST..)=0x%04X calc(DD..)=0x%04X swap=0x%04X\r\n", rxChecksum, calculatedChecksum, calc_from_dd, rx_swapped);
            HAL_UART_Transmit(&huart1, (uint8_t*)dbg, n, 0xFFFF);
            return 0;
        }
    }

    // 填充BMS响应结构体
    bmsResponse.header = rawData[0];
    bmsResponse.cmd = rawData[1];
    bmsResponse.status = status;
    bmsResponse.dataLen = dataLen;
    memcpy(bmsResponse.data, &rawData[4], dataLen);
    bmsResponse.checksum = rxChecksum;
    bmsResponse.stopByte = rawData[rawLen-1];

    return 1; // 解析成功
}

// 打印BMS数据（按新协议字段解析）
void printBMSData(BMS_Response_t *bms)
{
    char debugMsg[256];
    int len;

    // 基本信息
    len = sprintf(debugMsg, "BMS Resp: H=0x%02X CMD=0x%02X ST=0x%02X Len=%u CS=0x%04X Stop=0x%02X\r\n",
                  bms->header, bms->cmd, bms->status, bms->dataLen, bms->checksum, bms->stopByte);
    HAL_UART_Transmit(&huart1, (uint8_t*)debugMsg, len, 0xFFFF);

    // 简要十六进制数据行
    len = sprintf(debugMsg, "Data: ");
    HAL_UART_Transmit(&huart1, (uint8_t*)debugMsg, len, 0xFFFF);
    for (uint16_t i = 0; i < bms->dataLen; i++)
    {
        len = sprintf(debugMsg, "%02X ", bms->data[i]);
        HAL_UART_Transmit(&huart1, (uint8_t*)debugMsg, len, 0xFFFF);
    }
    HAL_UART_Transmit(&huart1, (uint8_t*)"\r\n", 2, 0xFFFF);

    if (bms->dataLen < 25) return; // 最小长度保护

    // 按字段解析
    uint16_t p = 0;
    uint16_t u16;
    int16_t i16;

    // 总电压（10mV单位）
    u16 = ((uint16_t)bms->data[p] << 8) | bms->data[p+1]; p += 2;
    uint32_t totalMv = (uint32_t)u16 * 10U;

    // 总电流（假定有符号，单位10mA，MSB为符号）
    u16 = ((uint16_t)bms->data[p] << 8) | bms->data[p+1]; p += 2;
    i16 = (int16_t)u16; // 两补码
    int32_t totalMa = (int32_t)i16 * 10;

    // 剩余容量/满充容量/循环次数（单位10mAh）
    u16 = ((uint16_t)bms->data[p] << 8) | bms->data[p+1]; p += 2;
    uint32_t remainMah = (uint32_t)u16 * 10U;
    u16 = ((uint16_t)bms->data[p] << 8) | bms->data[p+1]; p += 2;
    uint32_t fullMah = (uint32_t)u16 * 10U;
    u16 = ((uint16_t)bms->data[p] << 8) | bms->data[p+1]; p += 2;
    uint16_t cycleCount = u16;

    // 生产日期（原始值输出）
    u16 = ((uint16_t)bms->data[p] << 8) | bms->data[p+1]; p += 2;
    uint16_t productionDateRaw = u16;

    // 均衡低/高
    uint16_t balanceLow = ((uint16_t)bms->data[p] << 8) | bms->data[p+1]; p += 2;
    uint16_t balanceHigh = ((uint16_t)bms->data[p] << 8) | bms->data[p+1]; p += 2;

    // 保护状态/软件版本/SOC/MOS/串数/NTC个数
    uint16_t protectStatus = ((uint16_t)bms->data[p] << 8) | bms->data[p+1]; p += 2;
    uint8_t swVersion = bms->data[p++];
    uint8_t socPct = bms->data[p++];
    uint8_t mosStatus = bms->data[p++];
    uint8_t seriesCount = bms->data[p++];
    uint8_t ntcCount = bms->data[p++];

    // NTC温度（每个2字节，单位0.1℃，算法：val - 2731）
    len = sprintf(debugMsg, "V=%.2fV I=%.2fA Rem=%lumAh Full=%lumAh Cyc=%u SOC=%u%% SW=0x%02X MOS=0x%02X Cells=%u NTC=%u DateRaw=0x%04X BalL=0x%04X BalH=0x%04X Prot=0x%04X\r\n",
                  totalMv/1000.0f, totalMa/1000.0f, (unsigned long)remainMah, (unsigned long)fullMah,
                  cycleCount, socPct, swVersion, mosStatus, seriesCount, ntcCount, productionDateRaw,
                  balanceLow, balanceHigh, protectStatus);
    HAL_UART_Transmit(&huart1, (uint8_t*)debugMsg, len, 0xFFFF);

    for (uint8_t i = 0; i < ntcCount && (p + 1) < bms->dataLen; i++)
    {
        u16 = ((uint16_t)bms->data[p] << 8) | bms->data[p+1]; p += 2;
        int32_t tenthsC = (int32_t)u16 - 2731; // 0.1℃
        len = sprintf(debugMsg, "T%u=%.1fC ", i + 1, tenthsC / 10.0f);
        HAL_UART_Transmit(&huart1, (uint8_t*)debugMsg, len, 0xFFFF);
    }
    HAL_UART_Transmit(&huart1, (uint8_t*)"\r\n", 2, 0xFFFF);

    // 设计容量（在NTC之后的2字节，单位10mAh）
    if ((p + 1) < bms->dataLen)
    {
        u16 = ((uint16_t)bms->data[p] << 8) | bms->data[p+1];
        uint32_t designMah = (uint32_t)u16 * 10U;
        len = sprintf(debugMsg, "DesignCap=%lumAh\r\n", (unsigned long)designMah);
        HAL_UART_Transmit(&huart1, (uint8_t*)debugMsg, len, 0xFFFF);
    }
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_USART3_UART_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
    HAL_UART_Receive_IT(&huart1, u1Rx, U1_RX_LEN);
    HAL_UARTEx_ReceiveToIdle_IT(&huart2, rs485Resp, RS485_RESP_LEN);  // 使用IDLE方式接收RS485响应
    HAL_UART_Receive_IT(&huart3, u3Rx, U3_RX_LEN);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
		
		
    /* USER CODE BEGIN 3 */
		
		// 连续发送机制：若未收到应答，按固定间隔重发
		uint32_t now = HAL_GetTick();
		if (!rs485TxFlag || (now - lastTxTick >= RS485_RESEND_INTERVAL_MS))
		{
			HAL_UART_Transmit(&huart1, (uint8_t*)"Sending RS485 command: ", 22, 0xFFFF);
			for (int i = 0; i < RS485_CMD_LEN; i++)
			{
				char cmdMsg[8];
				int len = sprintf(cmdMsg, "%02X ", rs485Cmd[i]);
				HAL_UART_Transmit(&huart1, (uint8_t*)cmdMsg, len, 0xFFFF);
			}
			HAL_UART_Transmit(&huart1, (uint8_t*)"\r\n", 2, 0xFFFF);
			if (HAL_UART_Transmit(&huart2, rs485Cmd, RS485_CMD_LEN, 50) != HAL_OK)
			{
				char err[64];
				sprintf(err, "USART2 TX ERR: hs=%lu, ec=%lu\r\n", (unsigned long)huart2.gState, (unsigned long)huart2.ErrorCode);
				HAL_UART_Transmit(&huart1, (uint8_t*)err, strlen(err), 0xFFFF);
			}
			rs485TxFlag = 1;
			lastTxTick = now;
		}
		
		// 处理RS485响应（IDLE方式得到实际长度）
		if (rs485RespFlag == 1)
		{
			// 从累积缓冲中尝试抽帧
			uint8_t printedAny = 0;
			while (1)
			{
				// 寻找DD 03并计算总长：DD 03 ST LEN DATA(N) CS(2) 77
				if (rs485AccLen < 5) break;
				int16_t idx = -1;
				for (uint16_t i = 0; i + 1 < rs485AccLen; i++)
				{
					if (rs485AccBuf[i] == BMS_HEADER && rs485AccBuf[i+1] == BMS_CMD_03) { idx = (int16_t)i; break; }
				}
				if (idx < 0)
				{
					// 丢弃除最后两个字节外的数据
					if (rs485AccLen > 2)
					{
						memmove(rs485AccBuf, &rs485AccBuf[rs485AccLen-2], 2);
						rs485AccLen = 2;
					}
					break;
				}
				if (idx > 0)
				{
					memmove(rs485AccBuf, &rs485AccBuf[idx], rs485AccLen - idx);
					rs485AccLen -= idx;
					if (rs485AccLen < 5) break;
				}
				uint8_t st = rs485AccBuf[2];
				uint8_t dl = rs485AccBuf[3];
				uint16_t total = 7 + dl;
				if (rs485AccLen < total) break; // 等待更多
				// 拿到一个完整帧
				memcpy(rs485Resp, rs485AccBuf, total);
				// 移除该帧
				memmove(rs485AccBuf, &rs485AccBuf[total], rs485AccLen - total);
				rs485AccLen -= total;

				HAL_UART_Transmit(&huart1, (uint8_t*)"Received RS485 Response: ", 24, 0xFFFF);
				for (uint16_t i = 0; i < total; i++)
				{
					char respMsg[8];
					int len = sprintf(respMsg, "%02X ", rs485Resp[i]);
					HAL_UART_Transmit(&huart1, (uint8_t*)respMsg, len, 0xFFFF);
				}
				HAL_UART_Transmit(&huart1, (uint8_t*)"\r\n", 2, 0xFFFF);

				if (parseBMSResponse(rs485Resp, total))
				{
					HAL_UART_Transmit(&huart1, (uint8_t*)"BMS Response parsed successfully!\r\n", 32, 0xFFFF);
					printBMSData(&bmsResponse);
					bmsParseFlag = 1;
					rs485TxFlag = 0; // 成功后允许再次发送
				}
				else
				{
					HAL_UART_Transmit(&huart1, (uint8_t*)"Failed to parse BMS response!\r\n", 30, 0xFFFF);
				}
				printedAny = 1;
			}
			rs485RespFlag = 0;
			(void)printedAny;
		}
		

    // if (u1RxFlag == 1)
    // {
    //     HAL_UART_Transmit(&huart1, "U2 send info to U3!\n", sizeof("U2 send info to U3!\n")-1, 0xFFFF);
    //     HAL_UART_Transmit(&huart2, "U2TOU3", 6, 0xFFFF);
    //     u1RxFlag = 0;
    // }
    // if (u2RxFlag == 1)
    // {
    //     HAL_UART_Transmit(&huart1, "U2 get info!\n", sizeof("U2 get info!\n")-1, 0xFFFF);
    //     HAL_UART_Transmit(&huart1, "RS485 test pass!\n", sizeof("RS485 test pass!\n")-1, 0xFFFF);
    //     u2RxFlag = 0;
    // }
    // if (u3RxFlag == 1)
    // {
    //     HAL_UART_Transmit(&huart1, "U3 get info!\n", sizeof("U3 get info!\n")-1, 0xFFFF);
    //     HAL_UART_Transmit(&huart1, "U3 send info to U2!\n", sizeof("U3 send info to U2!\n")-1, 0xFFFF);
    //     HAL_UART_Transmit(&huart3, "U3TOU2", 6, 0xFFFF);
    //     u3RxFlag = 0;
    // }
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = 64;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 30;
  RCC_OscInitStruct.PLL.PLLP = 1;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
